package com.bestcem.xm.award.service.impl;

import cn.hutool.core.lang.Dict;
import cn.hutool.core.lang.Validator;
import com.bestcem.bp.grpc.v1.base.Code;
import com.bestcem.xm.award.config.FileConfig;
import com.bestcem.xm.award.constant.Constants;
import com.bestcem.xm.award.constant.RedisKeyConstant;
import com.bestcem.xm.award.constant.RequestAwardConstants;
import com.bestcem.xm.award.controller.convert.AwardConvert;
import com.bestcem.xm.award.dao.AwardWinDao;
import com.bestcem.xm.award.dao.DrawRecordDao;
import com.bestcem.xm.award.entity.mongo.BaseEntity;
import com.bestcem.xm.award.entity.pojo.AwardAwardDO;
import com.bestcem.xm.award.entity.pojo.AwardRecordDO;
import com.bestcem.xm.award.entity.pojo.AwardRequestDO;
import com.bestcem.xm.award.entity.pojo.AwardWinDO;
import com.bestcem.xm.award.enums.*;
import com.bestcem.xm.award.grpc.client.DeliverGrpcService;
import com.bestcem.xm.award.grpc.service.param.draw.*;
import com.bestcem.xm.award.mq.dto.DrawAwardSendSmsDTO;
import com.bestcem.xm.award.mq.dto.DrawAwardStartDTO;
import com.bestcem.xm.award.mq.dto.DrawAwardStopDTO;
import com.bestcem.xm.award.service.AwardDrawDisplayService;
import com.bestcem.xm.award.service.AwardMqHandler;
import com.bestcem.xm.award.service.DrawCommonService;
import com.bestcem.xm.award.service.bo.award.AwardAwardBO;
import com.bestcem.xm.award.service.bo.award.AwardWinBO;
import com.bestcem.xm.award.service.bo.award.WinDataBO;
import com.bestcem.xm.award.service.dto.FileInfoDTO;
import com.bestcem.xm.award.service.dto.awardaward.CreateAwardDTO;
import com.bestcem.xm.award.service.dto.awardaward.DeleteAwardDTO;
import com.bestcem.xm.award.service.dto.awardaward.UpdateAwardDTO;
import com.bestcem.xm.award.service.dto.awardaward.UpdateAwardStatusDTO;
import com.bestcem.xm.award.service.dto.draw.*;
import com.bestcem.xm.award.service.dto.requestaward.DrawAwardDTO;
import com.bestcem.xm.award.service.dto.requestaward.RequestAwardDTO;
import com.bestcem.xm.award.service.mq.send.AwardMessageService;
import com.bestcem.xm.award.util.DrawUtil;
import com.bestcem.xm.common.core.domain.web.PageResultDTO;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.oss.enums.OssPathEnum;
import com.bestcem.xm.common.core.uitls.*;
import com.bestcem.xm.componet.filestorage.service.StorageService;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.componet.sms.SmsService;
import com.bestcem.xm.deliver.grpc.v1.services.GetDeliverInfoRequest;
import com.bestcem.xm.deliver.grpc.v1.services.GetDeliverInfoResponse;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.io.File;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.bestcem.xm.award.constant.ColumnConstant.AwardAward.BASIC_TOTAL;
import static com.bestcem.xm.award.constant.ColumnConstant.AwardAward.RULE;
import static com.bestcem.xm.award.constant.Constants.AWARD_SMS_CODE_TEMPLATE;
import static com.bestcem.xm.award.constant.Constants.AWARD_SMS_CODE_TEMPLATE_10MIN;
import static com.bestcem.xm.award.constant.RedisKeyConstant.*;
import static com.bestcem.xm.award.enums.AwardRequestStatusEnum.PASS;
import static com.bestcem.xm.award.enums.AwardStatusEnum.INACTIVE;
import static com.bestcem.xm.award.enums.AwardTypeEnum.DRAW;

/**
 * 抽奖相关服务实现
 *
 * @author hang.li <hang.li@idiaoyan.com>
 * @version v1.0
 * @date 2021/6/30 17:47
 */
@Slf4j
@Service(value = "DrawAwardServiceImpl")
public class DrawAwardServiceImpl extends AbstractAwardAwardService implements AwardDrawDisplayService {

    @Resource(name = "recordDaoMysql")
    protected DrawRecordDao recordDao;

    @Resource(name = "winDaoMysql")
    protected AwardWinDao winDao;

    @Resource
    private DrawCommonService drawCommonService;

    /*@Resource
    private OssService ossService;*/

    @Resource
    private FileConfig fileConfig;

    @Resource
    private DeliverGrpcService deliverGrpcService;

    //@Resource
    //private SmsGrpcService smsGrpcService;

    @Resource
    private SmsService smsService;

    @Resource
    private AwardMqHandler awardMqHandler;

    @Resource
    protected AwardDispatcher awardDispatcher;
//    @Autowired
//    private RabbitMqConstantConfig rabbitMqConstantConfig;
//
//    @Resource
//    protected RabbitMessageSender rabbitMessageSender;

    @Value("${app.award.sms:true}")
    private boolean isSms;

    @Autowired
    private AwardMessageService awardMessageService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private StorageService storageService;

    /**
     * @param createAwardDTO 创建奖励入参
     * @return 创建结果(奖励id)
     */
    @Override
    public ServiceResult<String> createAward(CreateAwardDTO createAwardDTO) {
        // 预设id
        createAwardDTO.getAwardAward().setId(new ObjectId().toString());
        // 保存兑奖码
        ServiceResult<String> result = saveWins(createAwardDTO.getAwardAward(), createAwardDTO.getWinData());
        if (!result.isSuccess()) {
            return result;
        }
        // 保存奖励数据
        AwardAwardDO awardAwardDO = awardAwardDao.save(AwardConvert.awardAwardBOToAwardAwardDO(createAwardDTO.getAwardAward()));
        sendMqMsg(awardAwardDO);

        return ServiceResult.success(awardAwardDO.getId());
    }

    /**
     * 发送延迟消息
     *
     * @param awardAwardDO 奖励元数据
     */
    @Override
    public void sendMqMsg(AwardAwardDO awardAwardDO) {
        sendMqStartMsg(awardAwardDO);
        sendMqStopMsg(awardAwardDO);
    }

    public void sendMqStartMsg(AwardAwardDO awardAwardDO) {
        DrawAwardStartDTO drawAwardStartDTO = new DrawAwardStartDTO();
        drawAwardStartDTO.setAwardId(awardAwardDO.getId());
        drawAwardStartDTO.setStartTime(awardAwardDO.getBasic().getStartTime());
//        try {
//            mqMessageSender.sendDelayMsg(rabbitMqConstantConfig.getAppBpAwardDelayExchange(), rabbitMqConstantConfig.getAppBpAwardDelayRoutingKey(), AwardMqConstant.DRAW_AWARD_START_TOPIC, drawAwardStartDTO, awardAwardDO.getBasic().getStartTime());
//        } catch (JsonProcessingException e) {
//            log.error("发送延迟开始抽奖奖励消息失败:" + awardAwardDO.getId(), e);
//        }
        //stream mq /2022.05.13
        awardMessageService.awardDrawStartSend(drawAwardStartDTO, awardAwardDO.getBasic().getStartTime());
    }

    public void sendMqStopMsg(AwardAwardDO awardAwardDO) {
        DrawAwardStopDTO drawAwardStopDTO = new DrawAwardStopDTO();
        drawAwardStopDTO.setAwardId(awardAwardDO.getId());
        drawAwardStopDTO.setStopTime(awardAwardDO.getBasic().getStopTime());
//        try {
//            mqMessageSender.sendDelayMsg(rabbitMqConstantConfig.getAppBpAwardDelayExchange(), rabbitMqConstantConfig.getAppBpAwardDelayRoutingKey(), AwardMqConstant.DRAW_AWARD_STOP_TOPIC, drawAwardStopDTO, awardAwardDO.getBasic().getStopTime());
//        } catch (JsonProcessingException e) {
//            log.error("发送延迟结束抽奖奖励消息失败:" + awardAwardDO.getId(), e);
//        }
        //stream mq /2022.05.13
        awardMessageService.awardDrawStopSend(drawAwardStopDTO, awardAwardDO.getBasic().getStopTime());
    }

    /**
     * 保存兑奖码数据
     *
     * @param awardAward 奖励
     * @param winData    兑奖码数据
     * @return 兑奖码保存结果
     */
    protected ServiceResult<String> saveWins(AwardAwardBO awardAward, WinDataBO winData) {
        Optional<AwardAwardBO> optional = Optional.of(awardAward);
        AwardIssueTypeEnum issueType = optional.map(AwardAwardBO::getIssue).map(AwardAwardBO.Issue::getMethod).map(issueMethod -> EnumUtil.getEnumByIndex(AwardIssueTypeEnum.class, issueMethod)).get();
        // 是否需要解析兑奖码 如果是寄送方式，或者系统生成兑奖码方式，无需解析wins
        if (AwardIssueTypeEnum.CODE == issueType && optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getTotalCount).orElse(0) > 0
                && !org.springframework.util.StringUtils.hasText(optional.map(AwardAwardBO::getIssue).map(AwardAwardBO.Issue::getPrefix).orElse(null))) {

            if (winData.getStatus() == WinCodeStatusEnum.SMALL_WIN.getIndex()) {
                // 解析数据
                List<AwardWinDO> winList = convertWinsList(awardAward.getId(), winData.getWins());
                HashMap<String, Integer> map = new HashMap<>(Constants.SIXTEEN);
                for (int i = 0; i < winList.size(); i++) {
                    String name = winList.get(i).getName();
                    map.put(name, map.getOrDefault(name, 0) + 1);
                }
                // 检查奖项数量
                for (int i = 0; i < awardAward.getAwards().size(); i++) {
                    if (map.getOrDefault(awardAward.getAwards().get(i).getName(), 0).intValue() != awardAward.getAwards().get(i).getNum()) {
                        return ServiceResult.fail("奖项" + awardAward.getAwards().get(i).getName() + "兑奖码数量与奖项数量不匹配");
                    }
                }
                // 删除老数据
                awardWinDao.deleteByAwardId(awardAward.getId());
                // 插入兑奖码数据
                awardWinDao.insertMany(winList);
            } else {
                return ServiceResult.fail("无兑奖码数据");
            }
        }
        return ServiceResult.success();
    }

    /**
     * 数据转换 从grpc获取数据 并根据code去重
     *
     * @param winsList 兑奖码List
     * @return 兑奖码数据
     */
    protected List<AwardWinDO> convertWinsList(String awardId, List<AwardWinBO> winsList) {
        if (CollectionUtils.isEmpty(winsList)) {
            return new ArrayList<>();
        }
        winsList = winsList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<AwardWinBO>(Comparator.comparing(AwardWinBO::getCode))), ArrayList::new));
        // 数据转换 并根据code去重
        return winsList.stream().map(awardWin -> {
            AwardWinDO win = new AwardWinDO();
            win.setAwardId(awardId);
            win.setCode(awardWin.getCode());
            win.setName(awardWin.getName());
            win.setLevel(awardWin.getLevel());
            win.setUsed(false);
            return win;
        }).collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<AwardWinDO>(Comparator.comparing(AwardWinDO::getCode))), ArrayList::new));
    }


    @Override
    public ServiceResult<String> updateAward(UpdateAwardDTO updateAwardDTO) {
        // 保存兑奖码数据
        ServiceResult<String> result = saveWins(updateAwardDTO.getAwardAward(), updateAwardDTO.getWinData());
        if (!result.isSuccess()) {
            return result;
        }
        // 更新奖励
        AwardAwardDO awardAwardDO = awardAwardDao.save(AwardConvert.awardAwardBOToAwardAwardDO(updateAwardDTO.getAwardAward()));
        sendMqMsg(awardAwardDO);
        return ServiceResult.success(awardAwardDO.getId());
    }

    /**
     * 更新奖励状态
     *
     * @param updateAwardStatusDTO 更新奖励入参
     * @return 状态修改结果
     */
    @Override
    public ServiceResult<String> updateAwardStatus(UpdateAwardStatusDTO updateAwardStatusDTO) {
        // 检查是否可以更新到新状态
        if (checkUpdateStatus(updateAwardStatusDTO.getStatus(), updateAwardStatusDTO.getOldStatus())) {
            // 再次检查
            AwardAwardDO awardAwardDO = awardAwardDao.findById(updateAwardStatusDTO.getAwardId());
            if (awardAwardDO == null) {
                return ServiceResult.fail("奖励不存在！");
            }
            AwardAwardDO update = new AwardAwardDO();
            update.setStatus(updateAwardStatusDTO.getStatus());
            update.setActivated(Boolean.TRUE);
            // 如果是开始抽奖，手动初始化奖池
            if (INACTIVE.getIndex() == updateAwardStatusDTO.getOldStatus()) {
                DrawAwardStartDTO drawAwardStartDTO = new DrawAwardStartDTO();
                drawAwardStartDTO.setAwardId(updateAwardStatusDTO.getAwardId());
                drawAwardStartDTO.setStartTime(awardAwardDO.getBasic().getStartTime());
                awardMqHandler.startDrawAward(drawAwardStartDTO);
                // 如果是激活，保存激活时间
                if (update.getBasic() == null) {
                    update.setBasic(new AwardAwardDO.Basic());
                }
                update.getBasic().setStartTime(DateUtil.getDate());
                long modifiedCount = awardAwardDao.updateByAwardId(updateAwardStatusDTO.getAwardId(), update);
                if (modifiedCount == 1) {
                    return ServiceResult.success();
                }
            } else {
                long modifiedCount = awardAwardDao.updateByIdAndStatus(updateAwardStatusDTO.getAwardId(), updateAwardStatusDTO.getOldStatus(), update);
                if (modifiedCount == 1) {
                    return ServiceResult.success();
                }
            }
        }
        return ServiceResult.fail("当前状态无法转移至新状态！");
    }

    /**
     * 删除奖励
     *
     * @param deleteAwardDTO 删除奖励参数
     * @return 删除结果
     */
    @Override
    public ServiceResult<Integer> deleteAward(DeleteAwardDTO deleteAwardDTO) {
        // 删除兑奖码
        winDao.deleteByAwardId(deleteAwardDTO.getAwardId());
        return super.deleteAward(deleteAwardDTO);
    }

    /**
     * 获取奖励类型
     *
     * @return 奖励类型枚举
     */
    @Override
    public AwardTypeEnum getAwardTypeEnum() {
        return DRAW;
    }

    @Override
    public ServiceResult<String> doRequestAward(RequestAwardDTO requestAwardDTO) {
        // 返回结构体
        DrawAwardDTO drawAwardDTO = new DrawAwardDTO();
        drawAwardDTO.setTType(getAwardTypeEnum().getIndex());

        // 奖励id
        String awardId = Optional.ofNullable(requestAwardDTO).map(RequestAwardDTO::getAwardAwardDO)
                .map(BaseEntity::getId).orElse(Constants.BLANK);
        if (StringUtils.isBlank(awardId)) {
            return ServiceResult.fail(RequestAwardConstants.MISSING_AWARD_ID);
        }
        drawCommonService.asyncRestoreAwardPool(awardId);

        // 校验
        AwardRequestStatusEnum checkTotal = awardCheck.getCheckTotalResult(requestAwardDTO);
        if (checkTotal.getIndex() != PASS.getIndex()) {
            return super.checkFail(requestAwardDTO.getAwardRequestDO(), checkTotal);
        }
        AwardRequestStatusEnum checkCostTime = awardCheck.getCheckCostTimeResult(requestAwardDTO);
        if (checkCostTime.getIndex() != PASS.getIndex()) {
            return super.checkFail(requestAwardDTO.getAwardRequestDO(), checkCostTime);
        }
        AwardRequestStatusEnum checkAccount = awardCheck.getCheckAccountResult(requestAwardDTO);
        if (checkAccount.getIndex() != PASS.getIndex()) {
            return super.checkFail(requestAwardDTO.getAwardRequestDO(), checkAccount);
        }
        AwardRequestStatusEnum checkSurveyScore = awardCheck.getCheckSurveyScoreResult(requestAwardDTO);
        if (checkSurveyScore.getIndex() != PASS.getIndex()) {
            return super.checkFail(requestAwardDTO.getAwardRequestDO(), checkSurveyScore);
        }

        // 奖励信息 返回信息只需要awards.level、awards.name、awards.desc、awards.img,issue.method、issue.tip
        AwardAwardDO awardAwardDO = requestAwardDTO.getAwardAwardDO();
        drawAwardDTO.setAwards(Optional.ofNullable(awardAwardDO).map(AwardAwardDO::getAwards).orElse(null));
        drawAwardDTO.setIssue(Optional.ofNullable(awardAwardDO).map(AwardAwardDO::getIssue).orElse(null));
        // 待插入AWARD_REQUEST数据
        AwardRequestDO request = Optional.ofNullable(requestAwardDTO).map(RequestAwardDTO::getAwardRequestDO).orElse(null);
        if (Validator.isNull(request)) {
            return ServiceResult.fail(RequestAwardConstants.MISSING_AWARD_REQUEST);
        }
        DrawAwardDTO.Award award = new DrawAwardDTO.Award();
        award.setAwardId(awardId);
        award.setDeliverId(Optional.ofNullable(requestAwardDTO).map(RequestAwardDTO::getAwardRequestDO)
                .map(AwardRequestDO::getDeliverDTO).map(AwardRequestDO.Deliver::getDeliverId).orElse(null));
        award.setSurveyId(Optional.ofNullable(requestAwardDTO).map(RequestAwardDTO::getAwardRequestDO)
                .map(AwardRequestDO::getSurvey).map(AwardRequestDO.Survey::getSurveyId).orElse(null));
        Long surveySeq = Optional.ofNullable(requestAwardDTO).map(RequestAwardDTO::getAwardRequestDO)
                .map(AwardRequestDO::getSurvey).map(AwardRequestDO.Survey::getSeq).orElse(null);
        award.setSurveySeq(surveySeq);
        award.setAwardPage(Validator.isNotNull(surveySeq) ? String.valueOf(surveySeq) : null);
        // 生成签名
        String drawAwardKey = signConfig.getAwardKey();
        Map<String, Object> map = JsonUtil.convertValueSnake(award, new TypeReference<Map<String, Object>>() {
        });
        String sig = SignUtil.genSign(map, drawAwardKey);
        award.setSig(sig);
        drawAwardDTO.setAward(award);
        request.setStatus(PASS.getIndex());
        // 插入AWARD_REQUEST数据
        awardRequestDao.insert(request);
        String data = JsonUtil.transferToJsonSnake(drawAwardDTO);
        return ServiceResult.success(data);
    }

    @Override
    public ServiceResult<String> independentCheckAward(AwardAwardBO awardAward) {
        ServiceResult<String> result = checkAward(awardAward);
        if (!result.isSuccess()) {
            return ServiceResult.fail(result.getMsg());
        }
        Optional<AwardAwardBO> optional = Optional.of(awardAward);
        List<AwardAwardBO.Award> awardList = awardAward.getAwards();
        int totalCount = optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getTotalCount).orElse(0);
        if (totalCount > 0) {
            if (awardList.stream().anyMatch(award -> award.getNum() == null || award.getNum() <= 0)) {
                return ServiceResult.fail("奖项数量缺失！");
            }
            int sum = awardList.stream().map(AwardAwardBO.Award::getNum).reduce(0, Integer::sum);
            if (sum > totalCount) {
                return ServiceResult.fail("所有奖项数量的和必须小于限制抽奖次数");
            }
        } else {
            awardAward.getBasic().setTotalCount(null);
        }
        if (awardList.stream().anyMatch(award -> award.getProb() == null || award.getProb().compareTo(BigDecimal.ZERO) <= 0)) {
            return ServiceResult.fail("奖项概率不能小于等于0！");
        }
        BigDecimal sumProb = BigDecimal.ZERO;
        for (AwardAwardBO.Award award : awardList) {
            sumProb = sumProb.add(award.getProb());
        }
        if (sumProb.compareTo(new BigDecimal(Constants.LONG_HUNDRED)) > 0) {
            return ServiceResult.fail("概率和不可大于100%");
        }
        Integer issueMethod = optional.map(AwardAwardBO::getIssue).map(AwardAwardBO.Issue::getMethod).orElse(-1);
        AwardIssueTypeEnum issueType = EnumUtil.getEnumByIndex(AwardIssueTypeEnum.class, issueMethod);
        if (issueType == null) {
            return ServiceResult.fail("发奖方式缺失！");
        }
        if (!org.springframework.util.StringUtils.hasText(optional.map(AwardAwardBO::getIssue).map(AwardAwardBO.Issue::getTip).orElse(null))) {
            return ServiceResult.fail("兑奖操作提示缺失！");
        }
        awardAward.setPage(null);
        return ServiceResult.success();
    }

    @Override
    public ServiceResult<String> beforeFinishAward(String awardId) {
        // 对于有数量限制的情况，使用redis存储奖池后需要清理奖池
        redisService.del(String.format(RedisKeyConstant.AWARD_POOL, awardId));
        return ServiceResult.success();
    }

    /**
     * 奖励数据校验
     *
     * @param awardAward 奖励数据
     * @return 校验结果
     */
    public ServiceResult<String> checkAward(AwardAwardBO awardAward) {
        Optional<AwardAwardBO> optional = Optional.of(awardAward);
        if (!optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getStartTime).isPresent() || awardAward.getBasic().getStartTime().getTime() < DateUtil.now().getTime()) {
            if (awardAward.getBasic() != null) {
                awardAward.getBasic().setStartTime(DateUtil.now());
            }
        }
        if (!optional.map(AwardAwardBO::getBasic).map(AwardAwardBO.Basic::getStopTime).isPresent()) {
            return ServiceResult.fail("奖励结束时间缺失！");
        }
        if (awardAward.getBasic().getStopTime().compareTo(awardAward.getBasic().getStartTime()) < 0) {
            return ServiceResult.fail("结束时间不能在开始时间或当前时间之前!");
        }
        if (log.isInfoEnabled()) {
            log.info(awardAward.getName() + ":" + awardAward.getBasic().getStartTime().getTime() + ":" + awardAward.getBasic().getStopTime().getTime());
        }
        List<AwardAwardBO.Award> awardList = optional.map(AwardAwardBO::getAwards).orElse(null);
        if (CollectionUtils.isEmpty(awardList)) {
            return ServiceResult.fail("奖项缺失！");
        }
        if (awardList.stream().anyMatch(award -> !org.springframework.util.StringUtils.hasText(award.getName()))) {
            return ServiceResult.fail("奖项名称缺失！");
        }
        if (awardList.stream().map(AwardAwardBO.Award::getName).anyMatch(name -> name.length() > Constants.TEN)) {
            return ServiceResult.fail(String.format("奖项名称超过%d字符", Constants.TEN));
        }
        if (awardList.stream().map(AwardAwardBO.Award::getName).collect(Collectors.toSet()).size() != awardList.size()) {
            return ServiceResult.fail("奖项名称，列表内唯一！");
        }
        if (awardList.stream().map(AwardAwardBO.Award::getLevel).collect(Collectors.toSet()).size() != awardList.size()) {
            return ServiceResult.fail("奖项等级，列表内唯一！");
        }
        return ServiceResult.success();
    }

    @Override
    public ServiceResult<Long> updateWinnerStatus(UpdateStatusParam param) {
        // 获取对应的奖励
        AwardAwardDO award = awardAwardDao.findByAwardIdAndOrgIdAndType(param.getAwardId(), param.getOrgId(), getAwardTypeEnum().getIndex());
        if (Objects.isNull(award)) {
            return ServiceResult.fail("奖励不存在");
        }
        for (String recordId : param.getRecordIds()) {
            // 获取对应中奖记录
            AwardRecordDO record = recordDao.getRecordByIdAndStatus(recordId, RecordStatusEnum.YES.getIndex());
            if (Objects.nonNull(record)) {
                Integer status = record.getWin().getStatus();
                if (status != AwardIssueStatusEnum.TODO.getIndex()) {
                    return ServiceResult.fail("id:" + recordId + ", 当前状态禁止修改");
                }
            } else {
                return ServiceResult.fail("id为" + recordId + "的中奖记录不存在");
            }
        }
        // 修改状态
        long count = recordDao.updateWinStatusById(param.getRecordIds(), AwardIssueStatusEnum.YES.getIndex());
        return ServiceResult.success(count);
    }

    @Override
    public ServiceResult<Long> saveWinnerMessage(SaveWinnerMessageParam param) {
        AwardRecordDO record = recordDao.getRecordByPageAndPhone(param.getAwardPage(), param.getPhone());
        if (Objects.isNull(record)) {
            return ServiceResult.fail("未进行过抽奖");
        }
        if (Objects.isNull(record.getWin())) {
            return ServiceResult.fail("未中奖");
        }
        boolean isArr = (AwardIssueTypeEnum.ADDR.getIndex() == record.getWin().getMethod());
        long count = recordDao.updateWinnerMessage(param, isArr);
        if (count < 1) {
            return ServiceResult.fail("信息保存失败");
        }
        return ServiceResult.success(count);
    }

    /*@Override
    public ServiceResult getSmsAuthCode(GetSmsCodeParam param) {
        // 短信验证码key
        String smsCodeKey = SMS_AUTH_CODE_PREFIX + param.getAwardId() + ":" + param.getDeliverId() + ":" + param.getPhone();
        // 请求频率验证
        String frequencyKey = String.format(SMS_FREQUENCY_KEY, smsCodeKey);
        long value = redisService.incr(frequencyKey, 1);
        if (value == 1) {
            redisService.expire(frequencyKey, SMS_FREQUENCY_TIMEOUT, TimeUnit.SECONDS);
        } else if (value > 1) {
            return ServiceResult.fail("请求过于频繁");
        }

        AwardAwardDO award = awardAwardDao.findById(param.getAwardId());
        if (Objects.isNull(award)) {
            return ServiceResult.fail("奖励不存在");
        }
        // 生成短信验证码
        String smsCodeValue = DrawUtil.generateCode("", 4);
        String orgId = award.getOrgId();
        String name = award.getName();
        String projectId = award.getProjectId();
        String smsContent = String.format(AWARD_SMS_CODE_TEMPLATE, smsCodeValue, AWARD_SMS_CODE_TEMPLATE_10MIN);
        if (isSms) {
            // 发送短信
            SendSmsRequest.Builder request = SendSmsRequest.newBuilder();
            request.setOrgId(orgId).setProjectId(projectId).setName(name).setPhone(param.getPhone())
                    .setContent(smsContent).setTypeValue(SmsRecordTypeEnum.SmsRecordType.DRAW_VALUE);
            try {
                SendSmsResponse smsResponse = smsGrpcService.sendSms(request.build());
                if (Code.OK_VALUE == smsResponse.getStatus().getCodeValue()) {
                    if (log.isInfoEnabled()) {
                        log.info("[award] 手机号{}, 发送短信验证码{}", param.getPhone(), smsCodeValue);
                    }
                } else {
                    log.error("[award] 手机号{}, 短信验证码发送失败: {}", param.getPhone(), smsResponse.getStatus().getMessage());
                    return ServiceResult.fail("短信验证码发送失败");
                }
            } catch (Exception e) {
                log.error("[award] 手机号{}, 短信服务调用错误:", param.getPhone(), e);
                return ServiceResult.fail("短信服务调用失败");
            }
        }
        // 保存验证码
        redisService.set(smsCodeKey, smsCodeValue, SMS_AUTH_CODE_TIMEOUT, TimeUnit.SECONDS);
        return ServiceResult.success();
    }*/

    @Override
    public ServiceResult getSmsAuthCode(GetSmsCodeParam param) {
        // 短信验证码key
        String smsCodeKey = SMS_AUTH_CODE_PREFIX + param.getAwardId() + ":" + param.getDeliverId() + ":" + param.getPhone();
        // 请求频率验证
        String frequencyKey = String.format(SMS_FREQUENCY_KEY, smsCodeKey);
        long value = redisService.incr(frequencyKey, 1);
        if (value == 1) {
            redisService.expire(frequencyKey, SMS_FREQUENCY_TIMEOUT, TimeUnit.SECONDS);
        } else if (value > 1) {
            return ServiceResult.fail("请求过于频繁");
        }

        AwardAwardDO award = awardAwardDao.findById(param.getAwardId());
        if (Objects.isNull(award)) {
            return ServiceResult.fail("奖励不存在");
        }
        // 生成短信验证码
        String smsCodeValue = DrawUtil.generateCode("", 4);
        String orgId = award.getOrgId();
        String name = award.getName();
        String projectId = award.getProjectId();
        String smsContent = String.format(AWARD_SMS_CODE_TEMPLATE, smsCodeValue, AWARD_SMS_CODE_TEMPLATE_10MIN);
        if (isSms) {
            // 发送短信
            try {
                Map<String, Object> map = smsService.sendSms(param.getPhone(), smsContent, null);
                if (!ObjectUtils.isEmpty(map)) {
                    if (log.isInfoEnabled()) {
                        log.info("[award] 手机号{}, 发送短信验证码{}", param.getPhone(), smsCodeValue);
                    }
                } else {
                    log.error("[award] 手机号{}, 短信验证码发送失败: {}", param.getPhone(), map);
                    return ServiceResult.fail("短信验证码发送失败");
                }
            } catch (Exception e) {
                log.error("[award] 手机号{}, 短信服务调用错误:", param.getPhone(), e);
                return ServiceResult.fail("短信服务调用失败");
            }
        }
        // 保存验证码
        redisService.set(smsCodeKey, smsCodeValue, SMS_AUTH_CODE_TIMEOUT, TimeUnit.SECONDS);
        return ServiceResult.success();
    }

    @Override
    public ServiceResult verifySmsAuthCode(VerifySmsCodeParam param) {
        if (isSms) {
            String smsCodeKey = SMS_AUTH_CODE_PREFIX + param.getAwardId() + ":" + param.getDeliverId() + ":" + param.getPhone();
            String smsCode = redisService.getString(smsCodeKey);
            // 验证码校验
            if (StringUtils.isBlank(smsCode) || !StringUtils.equals(smsCode, param.getCode())) {
                return ServiceResult.fail("验证码错误");
            }
        }
        // 判断awardPage是否被使用过
        AwardRecordDO awardRecord = recordDao.getRecordByAwardPage(param.getAwardPage());
        if (Objects.nonNull(awardRecord)) {
            return ServiceResult.fail("已进行过抽奖");
        }
        // 判断奖励是否被激活
        AwardAwardDO award = awardAwardDao.findByIdAndStatusAndType(param.getAwardId(), AwardStatusEnum.ACTIVE.getIndex(), getAwardTypeEnum().getIndex(), new String[]{RULE, BASIC_TOTAL}, null);
        if (Objects.isNull(award)) {
            return ServiceResult.fail("奖励已失效");
        }

        // 封装抽奖记录信息
        AwardRecordDO.Award recordAward = new AwardRecordDO.Award();
        recordAward.setAwardId(param.getAwardId());
        recordAward.setDeliverId(param.getDeliverId());
        // 获取投放信息
        GetDeliverInfoRequest.Builder request = GetDeliverInfoRequest.newBuilder();
        request.setId(param.getDeliverId());
        try {
            GetDeliverInfoResponse response = deliverGrpcService.getDeliver(request.build());
            if (Code.OK_VALUE == response.getStatus().getCodeValue()) {
                recordAward.setDeliverSource(response.getDeliver().getSourceValue());
                recordAward.setDeliverName(response.getDeliver().getName());
            } else {
                log.error("[award] deliverId: {}, 调用投放服务失败: {}", param.getDeliverId(), response.getStatus().getMessage());
            }
        } catch (Exception e) {
            log.error("[award] deliverId: {}, 调用投放服务错误:", param.getDeliverId(), e);
        }
        recordAward.setPhone(param.getPhone());
        recordAward.setAwardPage(param.getAwardPage());
        recordAward.setSurveyId(param.getSurveyId());
        recordAward.setSurveySeq(Long.valueOf(param.getAwardPage()));
        AwardRecordDO record = new AwardRecordDO();
        record.setAward(recordAward);
        record.setAwardId(param.getAwardId());
        record.setPhone(param.getPhone());

        // 判断奖励的抽奖次数是否达到上限
        if (Objects.nonNull(award.getBasic()) && Objects.nonNull(award.getBasic().getTotalCount())
                && recordDao.getAwardAlreadyDrawTotal(param.getAwardId()) >= award.getBasic().getTotalCount()) {
            record.setStatus(RecordStatusEnum.TOTAL.getIndex());
            recordDao.insertDrawRecord(record);
            return ServiceResult.fail("奖励抽奖次数已达上限");
        }
        // 检查用户抽奖次数
        if (Objects.nonNull(award.getRule()) && Objects.nonNull(award.getRule().getDraw())
                && recordDao.getDrawTotalByPhone(param.getAwardId(), param.getPhone()) >= award.getRule().getDraw()) {
            record.setStatus(RecordStatusEnum.DRAW.getIndex());
            recordDao.insertDrawRecord(record);
            return ServiceResult.fail("手机号抽奖次数已达上限");
        }
        // 检查用户中奖次数
        if (Objects.nonNull(award.getRule()) && Objects.nonNull(award.getRule().getWin())
                && recordDao.getWinTotalByPhone(param.getAwardId(), param.getPhone()) >= award.getRule().getWin()) {
            record.setStatus(RecordStatusEnum.WIN.getIndex());
            recordDao.insertDrawRecord(record);
            return ServiceResult.fail("手机号中奖次数已达上限");
        }
        // 验证通过
        record.setStatus(RecordStatusEnum.PASS.getIndex());
        recordDao.insertDrawRecord(record);
        return ServiceResult.success();
    }

    @Override
    public ServiceResult<PageResultDTO<RecordDTO>> listWinners(GetWinnersParam param) {
        // 获取奖励信息
        AwardAwardDO award = awardAwardDao.findByAwardIdAndOrgIdAndType(param.getAwardId(), param.getOrgId(), getAwardTypeEnum().getIndex());
        if (Objects.isNull(award)) {
            return ServiceResult.fail("奖励不存在");
        }
        List<RecordDTO> dtoList = new ArrayList<>();
        // 指定了record_id,只取这一条记录
        if (StringUtils.isNotBlank(param.getRecordId())) {
            AwardRecordDO record = recordDao.getRecordByIdsAndStatus(param.getAwardId(), param.getRecordId(), param.getDeliverId(), null);
            if (Objects.isNull(record)) {
                return ServiceResult.fail("抽奖记录不存在");
            }
            dtoList.add(RecordDTO.awardRecordToRecordDTO(record));
            return ServiceResult.success(new PageResultDTO<>(dtoList, 1L));
        }
        // 分页查询
        PageDTO<AwardRecordDO> recordPageDTO = recordDao.getRecordListByPage(param, param.getPage());
        for (AwardRecordDO record : recordPageDTO.getData()) {
            dtoList.add(RecordDTO.awardRecordToRecordDTO(record));
        }
        return ServiceResult.success(new PageResultDTO<>(dtoList, recordPageDTO.getTotal()));
    }

    @Override
    public ServiceResult<PageResultDTO<RecordDetailDTO>> listWinnerDetails(ListWinnerDetailsParam param) {
        // 获取奖励信息
        AwardAwardDO award = awardAwardDao.findByAwardIdAndOrgIdAndType(param.getAwardId(), param.getOrgId(), getAwardTypeEnum().getIndex());
        if (Objects.isNull(award)) {
            return ServiceResult.fail("奖励不存在");
        }
        List<RecordDetailDTO> dtoList = new ArrayList<>();
        // 指定了record_id，则只查询这一条记录
        if (StringUtils.isNotBlank(param.getRecordId())) {
            AwardRecordDO record = recordDao.getRecordByIdsAndStatus(param.getAwardId(), param.getRecordId(), param.getDeliverId(), RecordStatusEnum.YES.getIndex());
            if (Objects.isNull(record)) {
                return ServiceResult.fail("中奖记录不存在");
            }
            dtoList.add(RecordDetailDTO.awardRecordToRecordDetailDTO(record));
            return ServiceResult.success(new PageResultDTO<>(dtoList, 1L));
        }

        PageDTO<AwardRecordDO> recordPageDTO = recordDao.getRecordDetailByPage(param, param.getPage(), getUploadCodeLevels(award.getAwards()));
        for (AwardRecordDO record : recordPageDTO.getData()) {
            dtoList.add(RecordDetailDTO.awardRecordToRecordDetailDTO(record));
        }
        return ServiceResult.success(new PageResultDTO<>(dtoList, recordPageDTO.getTotal()));
    }

    @Override
    public ServiceResult<FileInfoDTO> exportWinners(ExportWinnersParam param) {
        // 获取奖励信息
        AwardAwardDO award = awardAwardDao.findByAwardIdAndOrgIdAndType(param.getAwardId(), param.getOrgId(), getAwardTypeEnum().getIndex());
        if (Objects.isNull(award)) {
            return ServiceResult.fail("奖励不存在");
        }
        List<AwardRecordDO> recordList = recordDao.getExportRecords(param);
        if (CollectionUtils.isEmpty(recordList)) {
            return ServiceResult.fail("未查询到可导出的抽奖记录");
        }
        List<ExportWinnersDTO> dtoList = new ArrayList<>();
        for (AwardRecordDO record : recordList) {
            dtoList.add(ExportWinnersDTO.awardRecordToExportWinnersDTO(record));
        }
        String awardName = award.getName();
        String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
        String fileName = awardName + "_中奖名单_" + date + ".xlsx";
        // 生成Excel数据
        File excelFile = ExcelExportUtil.createExcelStream(dtoList, ExportWinnersDTO.class, fileConfig.getTempFilePath());
        //String ossUrl = ossService.uploadTempFile(excelFile, fileName, OssPathEnum.TEMP_AWARD, Constants.OSS_TEMP_EXPIRE_SECOND, null, "奖励-中奖名单导出");
        String ossUrl = storageService.upload(excelFile, fileName, OssPathEnum.TEMP_AWARD.getPath(), new Dict()).getUrl();
        if (Objects.nonNull(excelFile)) {
            excelFile.delete();
        }
        if (log.isInfoEnabled()) {
            log.info("[Award]中奖名单文件导出,url:{}", ossUrl);
        }
        return ServiceResult.success(new FileInfoDTO("", fileName, ossUrl));
    }

    @Override
    public ServiceResult<FileInfoDTO> exportWinnerDetails(ExportWinnerDetailsParam param) {
        // 获取奖励信息
        AwardAwardDO award = awardAwardDao.findByAwardIdAndOrgIdAndType(param.getAwardId(), param.getOrgId(), getAwardTypeEnum().getIndex());
        if (Objects.isNull(award)) {
            return ServiceResult.fail("奖励不存在");
        }
        List<AwardRecordDO> recordList = recordDao.getExportRecordDetails(param, getUploadCodeLevels(award.getAwards()));
        if (CollectionUtils.isEmpty(recordList)) {
            return ServiceResult.fail("未查询到已发放兑奖码的信息");
        }
        List<ExportWinnerDetailDTO> dtoList = new ArrayList<>();
        for (AwardRecordDO record : recordList) {
            dtoList.add(ExportWinnerDetailDTO.awardRecordToExportWinnerDetailDTO(record));
        }
        String awardName = award.getName();
        String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
        String fileName = awardName + "_已发放兑奖码明细_" + date + ".xlsx";
        // 生成Excel数据
        File excelFile = ExcelExportUtil.createExcelStream(dtoList, ExportWinnerDetailDTO.class, fileConfig.getTempFilePath());
        //String ossUrl = ossService.uploadTempFile(excelFile, fileName, OssPathEnum.TEMP_AWARD, Constants.OSS_TEMP_EXPIRE_SECOND, null, "奖励-已发放兑奖码明细导出");
        String ossUrl = storageService.upload(excelFile, fileName, OssPathEnum.TEMP_AWARD.getPath(), new Dict()).getUrl();
        if (Objects.nonNull(excelFile)) {
            excelFile.delete();
        }
        if (log.isInfoEnabled()) {
            log.info("[Award] 抽奖已发放兑奖码明细导出,url:{}", ossUrl);
        }
        return ServiceResult.success(new FileInfoDTO("", fileName, ossUrl));
    }

    @Override
    public ServiceResult<GetAwardDetailDTO> getAwardDetail(GetAwardDetailParam param) {
        // 获取奖励信息
        AwardAwardDO award = awardAwardDao.findByAwardIdAndOrgIdAndType(param.getAwardId(), param.getOrgId(), getAwardTypeEnum().getIndex());
        if (Objects.isNull(award)) {
            return ServiceResult.fail("奖励不存在");
        }
        // 奖项List
        List<AwardAwardDO.Award> awardList = award.getAwards();
        if (CollectionUtils.isEmpty(awardList)) {
            return ServiceResult.fail("奖励没有奖项可供统计");
        }
        GetAwardDetailDTO detailDTO = new GetAwardDetailDTO();
        // 未中奖次数
        long failCount = recordDao.getNoWinCountById(param.getAwardId(), param.getDeliverId());
        // 聚合统计
        List<AwardDetailDTO> dtoList = recordDao.getAwardDetailByAgg(param.getAwardId(), param.getDeliverId(), RecordStatusEnum.YES.getIndex());
        // 中奖次数
        long winCount = 0;
        Map<String, Integer> awardInfoMap = new HashMap<>(16);
        if (!CollectionUtils.isEmpty(dtoList)) {
            for (AwardDetailDTO awardDetailDTO : dtoList) {
                winCount += awardDetailDTO.getWinCount();
                awardInfoMap.put(awardDetailDTO.getName(), awardDetailDTO.getLevel());
            }
        }
        detailDTO.setWinCount((int) winCount).setFailCount((int) failCount);
        List<AwardDetailDTO> dtoArrayList = new ArrayList<>(dtoList);
        // 防止未被抽奖的奖项被漏统计
        if (dtoArrayList.size() < awardList.size()) {
            for (AwardAwardDO.Award award1 : awardList) {
                if (awardInfoMap.get(award1.getName()) == null) {
                    AwardDetailDTO awardDetailDTO = new AwardDetailDTO();
                    awardDetailDTO.setLevel(award1.getLevel())
                            .setName(award1.getName())
                            .setWinCount(0);
                    dtoArrayList.add(awardDetailDTO);
                }
            }
        }
        // 如果奖励存在数量限制，则设置奖项数量
        if (Objects.nonNull(award.getBasic().getTotalCount())) {
            Map<Integer, Integer> infoMap = new HashMap<>(16);
            for (AwardAwardDO.Award award1 : awardList) {
                infoMap.put(award1.getLevel(), award1.getNum());
            }
            for (AwardDetailDTO awardDetailDTO : dtoArrayList) {
                awardDetailDTO.setAwardCount(infoMap.get(awardDetailDTO.getLevel()));
            }
        }
        dtoArrayList.sort((AwardDetailDTO o1, AwardDetailDTO o2) -> (o1.getLevel() > o2.getLevel() ? 1 : -1));
        detailDTO.setAwardDetailDTOList(dtoArrayList);
        return ServiceResult.success(detailDTO);
    }

    @Override
    public ServiceResult<DrawAwardResultDTO> drawAward(DrawAwardParam param) {
        AwardAwardDO award = awardAwardDao.findByIdAndStatusAndType(param.getAwardId(), AwardStatusEnum.ACTIVE.getIndex(), getAwardTypeEnum().getIndex(), null, null);
        if (Objects.isNull(award)) {
            return ServiceResult.fail("奖励已失效");
        }
        AwardRecordDO record = recordDao.getRecordByAwardPageAndStatus(param.getAwardPage(), RecordStatusEnum.PASS.getIndex());
        if (Objects.isNull(record)) {
            if (log.isInfoEnabled()) {
                log.info("[award] awardPage:{}, 未查询到请求通过的记录无法进行抽奖, 请求参数param:{}", param.getAwardPage(), param);
            }
            return ServiceResult.fail("无法进行抽奖");
        }
        // 抽奖过程加锁
        redisService.lock(String.format(RedisKeyConstant.DRAW_AWARD_LOCK_KEY, param.getAwardId()));
        try {
            // 锁内二次判断
            AwardRecordDO record2 = recordDao.getRecordByAwardPageAndStatus(param.getAwardPage(), RecordStatusEnum.PASS.getIndex());
            if (Objects.isNull(record2)) {
                if (log.isInfoEnabled()) {
                    log.info("[award] awardPage:{}, 未查询到请求通过的记录无法进行抽奖, 请求参数param:{}", param.getAwardPage(), param);
                }
                return ServiceResult.fail("无法进行抽奖");
            }
            // 检查抽奖总数
            if (Objects.nonNull(award.getBasic()) && Objects.nonNull(award.getBasic().getTotalCount())
                    && recordDao.getAwardAlreadyDrawTotal(param.getAwardId()) >= award.getBasic().getTotalCount()) {
                recordDao.updateRecordStatusByAwardPage(param.getAwardPage(), RecordStatusEnum.TOTAL.getIndex());
                return ServiceResult.fail("奖励抽奖次数已达上限");
            }
            // 检查用户抽奖次数
            if (Objects.nonNull(award.getRule()) && Objects.nonNull(award.getRule().getDraw())
                    && recordDao.getDrawTotalByPhone(param.getAwardId(), param.getPhone()) >= award.getRule().getDraw()) {
                recordDao.updateRecordStatusByAwardPage(param.getAwardPage(), RecordStatusEnum.DRAW.getIndex());
                return ServiceResult.fail("手机号抽奖次数已达上限");
            }
            // 检查用户中奖次数
            if (Objects.nonNull(award.getRule()) && Objects.nonNull(award.getRule().getWin())
                    && recordDao.getWinTotalByPhone(param.getAwardId(), param.getPhone()) >= award.getRule().getWin()) {
                recordDao.updateRecordStatusByAwardPage(param.getAwardPage(), RecordStatusEnum.WIN.getIndex());
                return ServiceResult.fail("手机号中奖次数已达上限");
            }
            // 奖项List
            List<AwardAwardDO.Award> awards = award.getAwards();
            if (CollectionUtils.isEmpty(awards)) {
                return ServiceResult.fail("奖励没有奖项可供抽奖");
            }
            // 抽奖
            DrawAwardResultDTO resultDTO;
            if (Objects.nonNull(award.getBasic()) && Objects.nonNull(award.getBasic().getTotalCount())) {
                // 限制奖励次数的抽奖方式
                resultDTO = doDrawLimit(param, award, awards);
            } else {
                resultDTO = createPoolUnlimited(param, award, awards);
            }
            if (Objects.nonNull(resultDTO)) {
                if (Objects.nonNull(award.getIssue()) && StringUtils.isNotBlank(award.getIssue().getSms())) {
                    DrawAwardSendSmsDTO smsDTO = new DrawAwardSendSmsDTO();
                    smsDTO.setAwardId(award.getId());
                    smsDTO.setAwardName(award.getName());
                    smsDTO.setOrgId(award.getOrgId());
                    smsDTO.setProjectId(award.getProjectId());
                    smsDTO.setName(resultDTO.getName());
                    smsDTO.setLevel(resultDTO.getLevel());
                    smsDTO.setLevelStr(resultDTO.getLevelStr());
                    smsDTO.setCode(resultDTO.getCode());
                    smsDTO.setPhone(record.getPhone());
                    smsDTO.setSmsContent(award.getIssue().getSms());
//                    try {
//                        rabbitMessageSender.sendMsg(rabbitMqConstantConfig.getAppBpTopicExchange(), AwardMqConstant.DRAW_AWARD_SEND_SMS, AwardMqConstant.DRAW_AWARD_SEND_SMS, smsDTO);
//                    } catch (Exception e) {
//                        log.error("[award/rabbitmq] awardId:{},发送中奖短信通知消息失败:", award.getId(), e);
//                    }
                    awardMessageService.awardDrawSmsSend(smsDTO);
                }
                if (Objects.nonNull(award.getBasic().getTotalCount())) {
                    // 增加领奖记录
                    drawCommonService.updateAwardAndSendNotification(param.getAwardId());
                }
                if (log.isInfoEnabled()) {
                    log.info("[award] 用户{}中奖, 奖励信息{}", param.getPhone(), resultDTO);
                }
                return ServiceResult.success(resultDTO);
            } else {
                // 标记未中奖
                recordDao.updateStatusByAwardPageAndStatus(param.getAwardPage(), RecordStatusEnum.NO.getIndex());
                return ServiceResult.success(new DrawAwardResultDTO());
            }
        } finally {
            redisService.unlock(String.format(RedisKeyConstant.DRAW_AWARD_LOCK_KEY, param.getAwardId()));
        }
    }

    /**
     * 限制次数的奖励抽奖方式实现
     *
     * @param param  抽奖请求参数
     * @param award  奖励信息
     * @param awards 奖项List
     * @return 抽奖结果
     */
    protected DrawAwardResultDTO doDrawLimit(DrawAwardParam param, AwardAwardDO award, List<AwardAwardDO.Award> awards) {
        // 是否中奖
        boolean isWin = false;
        DrawAwardResultDTO resultDTO = new DrawAwardResultDTO();
        String value = redisService.lRightPop(String.format(RedisKeyConstant.AWARD_POOL, param.getAwardId()));
        if (StringUtils.isNotBlank(value) && !StringUtils.equals(Constants.MINUS_ONE_STRING, value) && Integer.parseInt(value) >= 0 && Integer.parseInt(value) < awards.size()) {
            isWin = true;
            AwardAwardDO.Award awardDetail = awards.get(Integer.parseInt(value));
            // 封装中奖信息
            AwardRecordDO.Win win = new AwardRecordDO.Win();
            handleWinInfo(win, awardDetail, resultDTO, award);
            doDrawLimitCheckMethod(award, win, awardDetail);
            // 修改抽奖记录
            recordDao.updateRecordWinByAwardPage(param.getAwardPage(), win);
            resultDTO.setCode(win.getCode()).setMethod(win.getMethod()).setLevelStr(win.getLevelStr());
        }
        if (Objects.nonNull(award.getRule()) && Objects.nonNull(award.getRule().getStopAward()) && award.getRule().getStopAward() && redisService.lLen(String.format(RedisKeyConstant.AWARD_POOL, param.getAwardId())) < 1) {
            // 结束奖励
            UpdateAwardStatusDTO updateAwardStatusDTO = new UpdateAwardStatusDTO();
            updateAwardStatusDTO.setAwardId(param.getAwardId());
            updateAwardStatusDTO.setStatus(AwardStatusEnum.FINISH.getIndex());
            updateAwardStatusDTO.setOldStatus(award.getStatus());
            updateAwardStatusDTO.setOrgId(award.getOrgId());
            ServiceResult<String> result = awardDispatcher.updateAwardStatus(updateAwardStatusDTO);
            if (result.isSuccess()) {
                log.info("[award] awardId:{},奖励结束", param.getAwardId());
            } else {
                log.info("[award] awardId:{},奖励结束失败:{}", param.getAwardId(), result.getMsg());
            }
        }
        return isWin ? resultDTO : null;
    }

    /**
     * 不限制次数的奖励抽奖方式实现
     *
     * @param param  抽奖请求参数
     * @param award  奖励信息
     * @param awards 奖项List
     * @return 抽奖结果
     */
    protected DrawAwardResultDTO createPoolUnlimited(DrawAwardParam param, AwardAwardDO award, List<AwardAwardDO.Award> awards) {
        // 是否中奖
        boolean isWin = false;
        DrawAwardResultDTO resultDTO = new DrawAwardResultDTO();
        Integer level = DrawUtil.createProbabilityPool(awards);
        if (Objects.nonNull(level)) {
            isWin = true;
            // 获取奖项
            AwardAwardDO.Award awardDetail = new AwardAwardDO.Award();
            for (AwardAwardDO.Award award1 : awards) {
                if (award1.getLevel().equals(level)) {
                    awardDetail = award1;
                    break;
                }
            }
            // 封装中奖信息
            AwardRecordDO.Win win = new AwardRecordDO.Win();
            handleWinInfo(win, awardDetail, resultDTO, award);
            createPoolUnlimitedCheckMethod(award, win, awardDetail);
            // 修改抽奖记录
            recordDao.updateRecordWinByAwardPage(param.getAwardPage(), win);
            resultDTO.setCode(win.getCode()).setMethod(win.getMethod()).setLevelStr(win.getLevelStr());
        }
        return isWin ? resultDTO : null;
    }

    /**
     * 判断奖项发放方式
     *
     * @param award       奖励
     * @param win         中奖信息
     * @param awardDetail 奖项信息
     */
    protected void doDrawLimitCheckMethod(AwardAwardDO award, AwardRecordDO.Win win, AwardAwardDO.Award awardDetail) {
        if (AwardIssueTypeEnum.CODE.getIndex() == award.getIssue().getMethod()) {
            win.setMethod(AwardIssueTypeEnum.CODE.getIndex());
            if (StringUtils.isNotBlank(award.getIssue().getPrefix())) {
                // 使用系统生成的兑奖码
                String prefix = award.getIssue().getPrefix();
                win.setCode(DrawUtil.generateCode(prefix, 14));
            } else {
                // 使用自定义兑奖码
                AwardWinDO awardWin = winDao.findAndUpdateByIdAndNameAndUsed(award.getId(), win.getName(), false);
                win.setCode(awardWin.getCode());
            }
        } else {
            win.setMethod(AwardIssueTypeEnum.ADDR.getIndex());
        }
    }

    /**
     * 判断奖项发放方式
     *
     * @param award       奖励
     * @param win         中奖信息
     * @param awardDetail 奖项信息
     */
    protected void createPoolUnlimitedCheckMethod(AwardAwardDO award, AwardRecordDO.Win win, AwardAwardDO.Award awardDetail) {
        if (AwardIssueTypeEnum.CODE.getIndex() == award.getIssue().getMethod()) {
            win.setMethod(AwardIssueTypeEnum.CODE.getIndex());
            String prefix = award.getIssue().getPrefix();
            win.setCode(DrawUtil.generateCode(prefix, 14));
        } else {
            win.setMethod(AwardIssueTypeEnum.ADDR.getIndex());
        }
    }

    /**
     * 获取手动上传兑奖码奖项等级
     *
     * @param awardList 奖项列表
     * @return 奖项等级List
     */
    public List<Integer> getUploadCodeLevels(List<AwardAwardDO.Award> awardList) {
        List<Integer> levelList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(awardList)) {
            for (AwardAwardDO.Award award : awardList) {
                boolean flag = (DRAW.getIndex() == getAwardTypeEnum().getIndex())
                        || (Objects.nonNull(award.getMethod())
                        && AwardIssueTypeEnum.CODE.getIndex() == award.getMethod()
                        && StringUtils.isBlank(award.getPrefix()));
                if (flag) {
                    levelList.add(award.getLevel());
                }
            }
        }
        return levelList;
    }

    /**
     * 封装中奖信息
     *
     * @param win         中奖信息
     * @param awardDetail 中奖奖项
     * @param resultDTO   抽奖结果
     * @param award       奖励信息
     */
    public void handleWinInfo(AwardRecordDO.Win win, AwardAwardDO.Award awardDetail, DrawAwardResultDTO resultDTO, AwardAwardDO award) {
        if (DRAW.getIndex() == getAwardTypeEnum().getIndex()) {
            if (Objects.nonNull(award.getIssue())) {
                resultDTO.setTip(award.getIssue().getTip());
            }
        } else {
            resultDTO.setTip(awardDetail.getTip());
        }
        resultDTO.setLevel(awardDetail.getLevel());
        resultDTO.setName(awardDetail.getName());
        win.setLevel(awardDetail.getLevel());
        win.setName(awardDetail.getName());
        win.setStatus(AwardIssueStatusEnum.TODO.getIndex());
        win.setWinTime(DateUtil.getDate());
        win.setLevelStr(awardDetail.getLevelStr());
    }
}